/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * This file is part of retabel.
 *
 * Copyright (c) 2011 by individual contributors as indicated by the
 * @author tags. See the copyright.txt file in the distribution
 * for a full listing of individual contributors.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */

package org.retabel.web.rest;

import org.retabel.persistence.entity.failover.FailureObject;
import org.retabel.service.failover.FailoverService;
import org.retabel.service.manager.FailureObjectManager;
import xsd.failureobjects.FailureObjectList;
import xsd.failureobjects.FailureObjects;
import xsd.failureobjects.ObjectFactory;

import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.ws.rs.*;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
import javax.xml.bind.JAXBElement;
import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar;
import java.util.GregorianCalendar;

/**
 * Failure object REST interface implementation
 * <p/>
 * <h3>Extra-Info</h3>
 * Created: 10:19 16.07.11
 *
 * @author Peter Herber
 * @version 1.0
 */
@Path("/render/failures/")
@Stateless
public class FailureObjectServiceBean extends RestServiceBean {

    /** The failure object manager. */
    @EJB
    private FailureObjectManager failureObjectManager;

    /** The failover service. */
    @EJB
    private FailoverService failoverService;

    /**
     * Retrieve a ranged list of available failure objects.
     *
     * @param first   the index of the first failure object to retrieve.
     * @param maxRows the maximum number of matches to retrieve.
     * @return xml containing the list of failure objects matching the given search criteria.
     * @throws javax.xml.datatype.DatatypeConfigurationException if an xml exception occurs.
     */
    @GET
    @Produces(MediaType.TEXT_XML)
    public Response getFailureObjects(@QueryParam("first") Integer first,
                                                         @QueryParam("maxRows") Integer maxRows)
        throws DatatypeConfigurationException {
        int maxRowsWithFallback = maxRows != null ? maxRows : getDefaultMaxResultsPerPage();
        int firstWithFallback = first != null ? first : 0;

        int count = failureObjectManager.count();
        FailureObject[] failureObjects = failureObjectManager.findRange(firstWithFallback, maxRowsWithFallback);

        ObjectFactory of = new ObjectFactory();

        FailureObjects result = of.createFailureObjects();
        result.setStart(firstWithFallback);
        result.setRows(failureObjects.length);
        result.setCount(count);

        FailureObjectList failureObjectList = of.createFailureObjectList();
        result.setList(failureObjectList);

        for (FailureObject failureObject : failureObjects) {
            xsd.failureobjects.FailureObject xmlFailureObject = of.createFailureObject();
            xmlFailureObject.setId(failureObject.getId());
            xmlFailureObject.setClassName(failureObject.getClassName());

            GregorianCalendar calendar = new GregorianCalendar();

            if (failureObject.getCreated() != null) {
                calendar.setTime(failureObject.getCreated());
                XMLGregorianCalendar xmlCalendar = DatatypeFactory.newInstance().newXMLGregorianCalendar(calendar);
                xmlFailureObject.setCreated(xmlCalendar);
            }

            if (failureObject.getLastRedo() != null) {
                calendar.setTime(failureObject.getLastRedo());
                XMLGregorianCalendar xmlCalendar = DatatypeFactory.newInstance().newXMLGregorianCalendar(calendar);
                xmlFailureObject.setLastRedo(xmlCalendar);
            }

            failureObjectList.getFailureObject().add(xmlFailureObject);
        }

        return Response.ok(result).build();
    }

    /**
     * Redo a failure object by it's unique id.
     *
     * @param id      the unique failure object id.
     * @param uriInfo the uri info context used for logging purposes.
     * @return plain/text log lines.
     */
    @PUT
    @Path("/{id}")
    @Produces(MediaType.TEXT_PLAIN)
    public Response redoFailureObject(@PathParam("id") Integer id, @Context UriInfo uriInfo) {
        PlainTextResponseBuilder response = new PlainTextResponseBuilder(uriInfo);

        if (id == null) {
            return Response.status(Response.Status.BAD_REQUEST).build();
        }

        FailureObject failureObject = failureObjectManager.findById(id);

        if (failureObject == null) {
            return Response.status(Response.Status.NOT_FOUND).build();
        }

        response.println("Attempting to retry failure object: " + id);

        failoverService.redo(id);

        return response.getResponse();
    }

    /**
     * Delete a failure object by it's unique id.
     *
     * @param id      the unique failure object id.
     * @param uriInfo the uri info context used for logging purposes.
     * @return plain/text log lines.
     */
    @DELETE
    @Path("/{id}")
    @Produces(MediaType.TEXT_PLAIN)
    public Response deleteFailureObject(@PathParam("id") Integer id, @Context UriInfo uriInfo) {
        PlainTextResponseBuilder response = new PlainTextResponseBuilder(uriInfo);

        response.println("Attempting to delete failure object: " + id);

        failureObjectManager.remove(id);

        return response.getResponse();
    }

}
